import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.Vector;


public class FileHandler {
	private int pieceSize;
	long fileSize;
	private String fileName;
	private RandomAccessFile filePointer;
	private Vector pieceCurrentlyWritten; // synchronize on this
	private int lastPieceNum;
	private int lastPieceSize;
	
	public FileHandler(String fileName, long fileSize, int pieceSize){
		this.pieceSize = pieceSize;
		this.fileName = fileName;
		this.fileSize = fileSize;
		lastPieceNum = (int) Math.floor(fileSize/pieceSize);
		if( ((lastPieceNum) * pieceSize) == fileSize){
			lastPieceNum -= 1;
		}
		lastPieceSize = (int) (fileSize - (pieceSize * lastPieceNum));
		pieceCurrentlyWritten = new Vector<Integer>();
		File file = new File(fileName);
		try {			
			if(!file.exists()){ 
				// Create the file
				file.createNewFile();
				filePointer = new RandomAccessFile(file, "rw");
				filePointer.setLength(fileSize);
			} else {
				filePointer = new RandomAccessFile(file, "rw");
			}			
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public void setPiece(byte[] buffer, int pieceNum){
		long position = pieceNum * pieceSize;
		
		if(pieceNum > lastPieceNum){
			System.err.println("ERROR: pieceNUM greater than filesize "+ pieceNum);
			return;
		}
		// Check if this piece is under writing process if so, return  else add this to Vector
		synchronized (pieceCurrentlyWritten) {
			if(pieceCurrentlyWritten.contains(pieceNum)){
				return;
			} else {
				pieceCurrentlyWritten.add(pieceNum);
			}
		}
		
		// Write to the file
		try {
			filePointer.seek(position);		
			filePointer.write(buffer);
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		// Notify readers waiting to read this piece
		synchronized (pieceCurrentlyWritten) {
			pieceCurrentlyWritten.remove(new Integer(pieceNum));
			pieceCurrentlyWritten.notifyAll();
		}
	}
	
	public byte[] getPiece(int pieceNum){
		long position = pieceNum * pieceSize;
		byte[] readBuffer;

		if(pieceNum > lastPieceNum){
			System.err.println("ERROR: pieceNUM greater than filesize "+ pieceNum);
			return null;
		}
		
		if(pieceNum == lastPieceNum){
			readBuffer = new byte[lastPieceSize];
		} else {
			readBuffer = new byte[pieceSize];
		}
		
		// Check if this piece is under writing process, if so wait for it
		synchronized (pieceCurrentlyWritten) {
			if(pieceCurrentlyWritten.contains(pieceNum)){
				try {
					pieceCurrentlyWritten.wait();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
		
		// Read the piece from file into readBuffer
		try{
			filePointer.seek(position);
			filePointer.read(readBuffer);
		} catch(IOException e){
			e.printStackTrace();
		}
		
		return readBuffer;
	}
	
	public void close(){
		try {
			filePointer.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}
